package com.bawei.es.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bawei.common.core.utils.StringUtils;
import com.bawei.es.domain.BulkDeleteDocs;
import com.bawei.es.domain.DocsQueryReq;
import com.bawei.es.domain.DocumentReq;
import com.bawei.es.domain.EsDocsQuery;
import com.bawei.es.service.EsDocumentService;
import com.bawei.es.sortEnum.SortEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author : zhangyu
 * @date  2023/11/14 16:31
 */
@Service
@Slf4j
@AllArgsConstructor
public class EsDocumentServiceImpl implements EsDocumentService {

    private RestHighLevelClient restHighLevelClient;

          /**
   * 插入文档
   *
   * @param documentReq 文档请求对象
   */
  @Override
  public void insertDocument(DocumentReq documentReq) {
      log.info("开始添加索引:{}",JSONObject.toJSONString(documentReq));

      // 检查索引是否存在
      if (!isExists(documentReq.getIndexName())) {
          throw new RuntimeException("查询索引失败");
      }
      IndexRequest indexRequest = new IndexRequest(documentReq.getIndexName());

      try {
          if(documentReq.getDocumentInfo()!=null){
              // 创建索引请求对象
              for (Map<String, Object> documentInfo : documentReq.getDocumentInfo()) {
                  if(documentInfo.containsKey(documentReq.getDocumentId()) && documentReq.isNeedId()==true){
                      String docId = documentInfo.get(documentReq.getDocumentId()).toString();
                      // 设置文档ID
                      indexRequest.id(docId);
                  }else {
                      throw new RuntimeException("文档信息不包含id");
                  }
                  indexRequest.source(documentReq.getDocumentInfo());
              }
          }
      }catch (Exception e){
          throw new RuntimeException("文档信息不能为空");
      }
      // 设置文档信息
      try {
          restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
      } catch (IOException e) {
          throw new RuntimeException("创建文档失败",e);
      }
      log.info("创建索引成功:{}",JSONObject.toJSONString(documentReq));

  }



    @Override
    public boolean isExists(String indexName) {

        //创建索引请求对象
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);

        try {
        //查询索引是否存在 存在 返回 true  不存在返回 false
            boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            return exists;
        } catch (IOException e) {
            throw new RuntimeException("索引查询失败",e);
        }

    }

    @Override
    public void deleteDocument(BulkDeleteDocs bulkDeleteDocs) {
        // 校验索引是否存在
        if (!isExists(bulkDeleteDocs.getIndexName())) {
            throw new RuntimeException("查询索引失败");
        }

        // 创建一个DeleteRequest对象，用于指定要删除的索引和文档ID

        for (Long id : bulkDeleteDocs.getIds()) {
            DeleteRequest deleteRequest = new DeleteRequest(bulkDeleteDocs.getIndexName());

            deleteRequest.id(String.valueOf(id));
            try {
                // 调用High Level Rest Client的delete方法，发送delete请求
                DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);

            } catch (Exception e) {
                // 捕获IOException，并抛出RuntimeException
                throw new RuntimeException("文档删除失败",e);
            }
        }



    }


        /**
     * 批量插入文档的方法
     * @param documentReq 插入的文档请求对象
     */
    @Override
    public void blukDocument(DocumentReq documentReq) {
        log.info("开始批量插入:{}",JSONObject.toJSONString(documentReq));

        // 检查索引是否存在
        if (!isExists(documentReq.getIndexName())) {
            throw new RuntimeException("查询索引失败");
        }

        // 创建一个BulkRequest对象
        BulkRequest bulkRequest = new BulkRequest();
        // 获取文档ID
        String documentId = documentReq.getDocumentId();


        // 获取要批量写入的文档列表
        List<Map<String, Object>> bulkDocument = documentReq.getDocumentInfo();

        for (Map<String, Object> bulk : bulkDocument) {
            // 创建一个IndexRequest对象
            IndexRequest indexRequest = new IndexRequest(documentReq.getIndexName());
            if(documentReq.isNeedId()){
                //判断是否为空 如果为空则不设置ID
                if(documentId!=null && bulk.containsKey(documentId)){
                    String docId = bulk.get(documentId).toString();
                    indexRequest.id(docId);
                }else{
                    throw new RuntimeException("文档id不能为空");
                }
            }else{
                throw new RuntimeException("未指定文档id");
            }
            //添加数据
            indexRequest.source(bulk);
            bulkRequest.add(indexRequest);
        }
        try {
            // 调用High Level Rest Client的bulk方法，发送bulk请求
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            //文档批量插入失败处理
            if(bulk.hasFailures()){
                for (BulkItemResponse bulkItemResponse : bulk) {
                    if(bulkItemResponse.isFailed()){
                        //处理失败文档
                        BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
                        log.info("批量插入失败：{}", JSONObject.toJSONString(failure));
                    }
                }
            }else {
                log.info("批量插入成功");
            }
        } catch (IOException e) {
            throw new RuntimeException("批量插入失败",e);
        }
    }


        @Override
    public void updateDocument(DocumentReq documentReq) {
        // 检查索引是否存在
        if (!isExists(documentReq.getIndexName())) {
            throw new RuntimeException("查询索引失败");
        }
        try {
            // 创建更新请求对象
            UpdateRequest updateRequest = new UpdateRequest();
            // 设置索引名称
            updateRequest.index(documentReq.getIndexName());
            // 设置文档ID
            updateRequest.id(documentReq.getDocumentId())
                    // 设置要更新的文档和文档类型
                    .doc(documentReq.getDocumentInfo(), XContentType.JSON);
            // 更新文档
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException("修改文档失败", e);
        }
    }

        @Override
    public EsDocsQuery docsQuery(DocsQueryReq docsQueryReq) {
        log.info("开始查询:{}",JSONObject.toJSONString(docsQueryReq));

        //总页数
            long total=0;
        // 检查索引是否存在
        if (!isExists(docsQueryReq.getIndexName())) {
            throw new RuntimeException("查询索引失败");
        }

        SearchRequest searchRequest = new SearchRequest(docsQueryReq.getIndexName());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();


            //        // 设置检索字段
//            if (docsQueryReq != null && docsQueryReq.getQueryFields() != null && docsQueryReq.getQueryFields().size() > 0) {
//                String[] fields = docsQueryReq.getQueryFields().toArray(new String[0]);
//                searchSourceBuilder.fetchSource(fields, null);
//            }

            // 设置全文检索关键字
            if (StringUtils.isNotEmpty(docsQueryReq.getKeyword())) {
                // 如果关键字非空
                if (docsQueryReq.getQueryFields() != null && docsQueryReq.getQueryFields().size() > 0) {
                    // 如果查询字段不为空且数量大于0
                    //循环检索字段
                    for (String queryField : docsQueryReq.getQueryFields()) {
                        // 遍历查询字段
                        boolQueryBuilder.should(QueryBuilders.matchQuery(queryField, docsQueryReq.getKeyword()));
                        // 添加匹配关键字在指定字段中的查询条件
                    }
                } else {
                    // 如果查询字段为空
                    // 全文检索*
                    boolQueryBuilder.must(QueryBuilders.multiMatchQuery(docsQueryReq.getKeyword()).field("*"));
                    // 使用 multiMatchQuery 构建查询，匹配关键字在所有字段中
                }
            }


            searchSourceBuilder.query(boolQueryBuilder);

        if (docsQueryReq.getPageReq().getPageNum()!= null&&
                docsQueryReq.getPageReq().getPageSize()!=null) {
            // 设置分页
            searchSourceBuilder.from((docsQueryReq.getPageReq().getPageNum() - 1)*docsQueryReq.getPageReq().getPageSize());
            searchSourceBuilder.size(docsQueryReq.getPageReq().getPageSize());
        }

        // 判断排序顺序
        if(SortEnum.DESC.getValue().equals(docsQueryReq.getDocsOrderReq().getType())){
            searchSourceBuilder.sort(docsQueryReq.getDocsOrderReq().getFiled(), SortOrder.DESC);
        }else {
            searchSourceBuilder.sort(docsQueryReq.getDocsOrderReq().getFiled(), SortOrder.ASC);
        }



        // 设置返回字段
        if (docsQueryReq.getReturnFields() != null && !docsQueryReq.getReturnFields().isEmpty()) {
            String[] fields = docsQueryReq.getReturnFields().toArray(new String[0]);
            searchSourceBuilder.fetchSource(fields, null);
        }
        searchRequest.source(searchSourceBuilder);
        log.info("查询条件:{}",searchSourceBuilder);
        try {
            // 执行查询
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = search.getHits();
            total=hits.getTotalHits().value;

            // 获取查询结果
            SearchHit[] hits1 = hits.getHits();
            List<Map<String, Object>> maps = new ArrayList<>();
            for (SearchHit hit : hits1) {
                maps.add(hit.getSourceAsMap());
            }
            EsDocsQuery esDocsQuery = new EsDocsQuery();

            esDocsQuery.setTotal(total);
            esDocsQuery.setList(maps);

            log.info("查询文档成功:{}",JSONObject.toJSONString(esDocsQuery));
            return esDocsQuery;
        } catch (IOException e) {
            throw new RuntimeException("查询文档失败",e);
        }
    }



}
